﻿using System;
using System.Diagnostics;
using System.Linq.Expressions;

namespace ExpressionMapper
{
    using MappingExpressionGenerator = Func<Expression, Type, Expression, ParameterExpression, Expression>;

    public static partial class Generators
    {
        /// <summary>
        /// Returns generator that uses Convert class for mapping.
        /// </summary>
        public static MappingExpressionGenerator UseObjectCasting()
        {
            return
                (fromExpr, to, customMapping, instanceDictionary) => {
                    if(IsObject(fromExpr.Type) && CanCast(to))
                    {
                        return customMapping ?? GenerateFromObjectCastExpression(fromExpr, to);
                    }
                    if(CanCast(fromExpr.Type) && IsObject(to))
                    {
                        return customMapping ?? GenerateToObjectCastExpression(fromExpr, to);
                    }
                                                                         return null;
                };
        }

        private static bool CanCast(Type t)
        {
            if (IsAssignable(t) || t.IsValueType || IsNullable(t) || t == typeof(Type))
                return true;

            return false;
        }

        public static bool IsObject(Type t)
        {
            return t == typeof(object);
        }

        private static Expression GenerateFromObjectCastExpression(Expression fromExpr, Type to)
        {
            Debug.WriteLine(string.Format("FromObjectCasting ({0}): {1} to {2}", fromExpr.NodeType, fromExpr.Type.Name,
                                  to.Name));
            return Expression.Convert(fromExpr, to);
        }

        private static Expression GenerateToObjectCastExpression(Expression fromExpr, Type to)
        {
            Debug.WriteLine(string.Format("ToObjectCasting ({0}): {1} to {2}", fromExpr.NodeType, fromExpr.Type.Name,to.Name));

            return Expression.Convert(fromExpr, to);
        }
    }
}
